package com.atguigu.srb.core.service.impl;

import com.alibaba.excel.EasyExcel;
import com.atguigu.srb.core.exception.BusinessException;
import com.atguigu.srb.core.listener.ExcelDictDTOLister;
import com.atguigu.srb.core.pojo.dto.ExcelDictDTO;
import com.atguigu.srb.core.pojo.entity.Dict;
import com.atguigu.srb.core.mapper.DictMapper;
import com.atguigu.srb.core.service.DictService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 数据字典 服务实现类
 * </p>
 *
 * @author AtLong
 * @since 2022-06-11
 */
@Service
@Slf4j
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Resource
    private DictMapper dictMapper;

    /**
     * 上传Exel到数据字典
     * String fileName = "F:/tmp/1655262210108.xlsx";
     * EasyExcel.read(fileName, ExcelStudentDTO.class, new  ExcelStudentDTOListener()).sheet().doRead();
     *
     * @param inputStream
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importExcelData(InputStream inputStream) {
        EasyExcel.read(inputStream, ExcelDictDTO.class, new ExcelDictDTOLister(baseMapper)).sheet().doRead();
        log.info("excel数据导入成功!");
    }

    /**
     * 下载Exel数据字典
     *
     * @return
     */
    @Override
    public List<ExcelDictDTO> listDictData() {
        List<Dict> dictList = baseMapper.selectList(null);
        //创建ExcelDictDTO列表,将Dict列表转换为ExcelDictDTO列表
        List<ExcelDictDTO> excelDictDTOS = new ArrayList<>(dictList.size());

        for (Dict dict : dictList) {
            ExcelDictDTO excelDictDTO = new ExcelDictDTO();
            BeanUtils.copyProperties(dict, excelDictDTO);
            excelDictDTOS.add(excelDictDTO);
        }
        return excelDictDTOS;
    }

    /**
     * 通过父节点查询子列表,查询列表
     *
     * @param parentId 父节点id
     * @return 返回子列表
     */
    @Override
    public List<Dict> getChildrenByPID(Long parentId) {
        List<Dict> dictList = null;
        //Prat01-----redis查询
        try {
            //1, 首先查询Redis中是否有数据列表
            dictList = (List<Dict>) redisTemplate.opsForValue().get("srb:core:dictList" + parentId);
            if (dictList != null) {
                //2, 如果存在,那么Redis中进行返回列表
                log.info("从redis中取值");
                return dictList;
            }
        } catch (Exception e) {
            log.info("redis服务异常:" + ExceptionUtils.getStackTrace(e));
        }
        //Prat02----- MySQL查询
        //3, 如果不存在,进行MySQL查询
        Assert.isNull(dictList, "数据列表为空");
        log.info("数据不存在redis,进行MySQL查询");
        QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
        queryWrapper = queryWrapper.eq("parent_id", parentId);
        dictList = baseMapper.selectList(queryWrapper);
        //遍历集合判断是否有子节点
        for (Dict dict : dictList) {
            Boolean res = this.hasChildren(dict.getId());
            dict.setHasChildren(res);
        }
        //Prat03-----查询到的数据redis进行缓存
        try {
            //4, 查询到数据将数据存入Redis数据库
            log.info("数据存入redis");
            redisTemplate.opsForValue().set("srb:core:dictList:" + parentId, dictList, 5, TimeUnit.MINUTES);
        } catch (Exception e) {
            log.error("redis服务器异常：" + ExceptionUtils.getStackTrace(e));//此处不抛出异常，继续执行后面的代码
        }
        //Prat04-----查询到的数据返回
        //5, 并且把查询到的数据返回
        return dictList;
    }

    @Override
    public List<Dict> findByDictCode(String dictCode) {
        QueryWrapper<Dict> dictQueryWrapper = new QueryWrapper<>();
        dictQueryWrapper.eq("dict_code", dictCode);
        Dict dict = baseMapper.selectOne(dictQueryWrapper);
        return this.getChildrenByPID(dict.getId());
    }


    @Override
    public String getNameByParentDictCodeAndValue(String dictCode, Integer value) {
         // 封装查询条件
        QueryWrapper<Dict> dictQueryWrapper1 = new QueryWrapper<>();
        dictQueryWrapper1.eq("dict_code",dictCode);
        Dict dictParent = baseMapper.selectOne(dictQueryWrapper1);
        Long dictParentId = dictParent.getId();

        QueryWrapper<Dict> dictQueryWrapper2 = new QueryWrapper<>();
        dictQueryWrapper2.eq("parent_id",dictParentId);
        dictQueryWrapper2.eq("value",value);
        Dict dict = baseMapper.selectOne(dictQueryWrapper2);

        return dict.getName();
    }

    /**
     * 判断是否有子节点
     *
     * @param id
     * @return
     */
    public Boolean hasChildren(Long id) {
        QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();
        queryWrapper = queryWrapper.eq("parent_id", id);
        Integer res = baseMapper.selectCount(queryWrapper);
        return res > 0;
    }
}
